package com.dji.sample.common.util;

import com.dji.sample.common.util.kmlModel.TravelRecordRequest;
import com.dji.sample.wayline.model.dto.UploadKmlDto;
import io.minio.ObjectWriteResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yjt
 * @date 2022-09-27
 * @description:
 */
@Component
@Slf4j
public class DjKmlUtil {
    @Value("${tmp.file.logo}")
    public String LOGO;

    @Value("${tmp.file.path}")
    public String TMP_PATH;

    @Autowired
    MinioUtil minioUtil;

    public static final String DJ_KML = "djkml/";

    //takeOffSecurityHeight 起飞高度  ellipsoidHeight全局航线高度 speed 速度
    public ObjectWriteResponse setTravelsKml(List<TravelRecordRequest> travelRecords, String takeOffSecurityHeight, String speed, Integer taskId, String ellipsoidHeight) throws Exception {
        Element root = DocumentHelper.createElement("kml");
        Document document = DocumentHelper.createDocument(root);

        //根节点添加属性
        root.addAttribute("xmlns", "http://www.opengis.net/kml/2.2")
                .addAttribute("xmlns:wpml", "http://www.dji.com/wpmz/1.0.0");


        Element documentElement = root.addElement("Document");
        documentElement.addNamespace("wpml", "http://www.dji.com/wpmz/1.0.0");
        documentElement.addAttribute("xmlns:wpml", "http://www.dji.com/wpmz/1.0.0");
        documentElement.addElement("wpml:createTime").addText(String.valueOf(System.currentTimeMillis()));
        documentElement.addElement("wpml:updateTime").addText(String.valueOf(System.currentTimeMillis()));

        Element missionConfig = documentElement.addElement("wpml:missionConfig");
        missionConfig.addElement("wpml:flyToWaylineMode").addText("safely");
        //航线结束动作goHome：飞行器完成航线任务后，退出航线模式并返航。
        //noAction：飞行器完成航线任务后，退出航线模式。
        //autoLand：飞行器完成航线任务后，退出航线模式并原地降落。
        //gotoFirstWaypoint：飞行器完成航线任务后，立即飞向航线起始点，到达后退出航线模式。* 注：以上动作执行过程，若飞行器退出了航线模式且进入失控状态，则会优先执行失控动作。
        missionConfig.addElement("wpml:finishAction").addText("goHome");
        //失控是否继续执行航线goContinue：继续执行航线 executeLostAction：退出航线，执行失控动作
        missionConfig.addElement("wpml:exitOnRCLost").addText("executeLostAction");
        //失控动作类型goBack：返航。飞行器从失控位置飞向起飞点
        //landing：降落。飞行器从失控位置原地降落
        //hover：悬停。飞行器从失控位置悬停
        missionConfig.addElement("wpml:executeRCLostAction").addText("goBack");
        //安全起飞高度m
        missionConfig.addElement("wpml:takeOffSecurityHeight").addText(takeOffSecurityHeight);
        //全局航线过渡速度m/s
        missionConfig.addElement("wpml:globalTransitionalSpeed").addText(speed);

        //飞行器机型信息
        Element droneInfo = missionConfig.addElement("wpml:droneInfo");
        droneInfo.addElement("wpml:droneEnumValue").addText("0");
        droneInfo.addElement("wpml:droneSubEnumValue").addText("0");
        //负载机型信息
        Element payloadInfo = missionConfig.addElement("wpml:payloadInfo");
        payloadInfo.addElement("wpml:payloadEnumValue").addText("0");
        payloadInfo.addElement("wpml:payloadSubEnumValue").addText("0");
        payloadInfo.addElement("wpml:payloadPositionIndex").addText("0");


        Element folderElement = documentElement.addElement("Folder");//添加一个目录
        folderElement.addElement("wpml:templateType").addText("waypoint");
        folderElement.addElement("wpml:useGlobalTransitionalSpeed").addText(speed);
        folderElement.addElement("wpml:templateId").addText(taskId.toString());
        folderElement.addElement("wpml:waylineId").addText(taskId.toString());
        Element waylineCoordinateSysParam = folderElement.addElement("wpml:waylineCoordinateSysParam");
        waylineCoordinateSysParam.addElement("wpml:coordinateMode").addText("WGS84");
        waylineCoordinateSysParam.addElement("wpml:heightMode").addText("EGM96");
        waylineCoordinateSysParam.addElement("wpml:ellipsoidHeight").addText(ellipsoidHeight);
        waylineCoordinateSysParam.addElement("wpml:height").addText(ellipsoidHeight);
        waylineCoordinateSysParam.addElement("wpml:positioningType").addText("GPS");

        folderElement.addElement("wpml:autoFlightSpeed").addText(speed.toString());
        //执行高度模式
        folderElement.addElement("wpml:transitionalSpeed").addText(speed.toString());
        folderElement.addElement("wpml:gimbalPitchMode").addText("usePointSetting");
        folderElement.addElement("wpml:globalWaypointHeadingParam").addElement("wpml:waypointHeadingMode").addText("followWayline");
        folderElement.addElement("wpml:globalWaypointTurnMode").addText("toPointAndStopWithDiscontinuityCurvature");


        //生成点位图标数据
        int i = 0;
        for (TravelRecordRequest travelRecord : travelRecords) {

            Element placeMarkElement = folderElement.addElement("Placemark");//在文件夹中添加一个地标
            Element pointElement = placeMarkElement.addElement("Point");
//            pointElement.addElement("altitudeMode").addText("clampToGround");
            //添加点位的经纬度坐标以及高度(显示时绘制高度m)
            pointElement.addElement("coordinates").addText(travelRecord.lng + "," + travelRecord.lat);//可以是是任何几何形状的子元素，定义每一个点的经度、纬度和高度(按照严格的顺序). 多个点使用空格隔开，经纬度按照WGS84标准.
            placeMarkElement.addElement("wpml:index").addText(String.valueOf(i));
            placeMarkElement.addElement("wpml:ellipsoidHeight").addText(ellipsoidHeight);
            placeMarkElement.addElement("wpml:height").addText(travelRecord.height);
            placeMarkElement.addElement("wpml:useGlobalHeight").addText("1");
            placeMarkElement.addElement("wpml:useGlobalSpeed").addText("1");
            placeMarkElement.addElement("wpml:useGlobalHeadingParam").addText("1");
            placeMarkElement.addElement("wpml:useGlobalTurnParam").addText("1");
            placeMarkElement.addElement("wpml:useStraightLine").addText("0");
            placeMarkElement.addElement("wpml:gimbalPitchAngle").addText("0");
            i++;
        }

        //新建文件夹
        String path = TMP_PATH + System.currentTimeMillis() + "/";
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        //创建kml到本地
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter kml = new XMLWriter(new FileOutputStream(path + "template" + ".kml"), format);
        kml.write(document);
        kml.close();

        XMLWriter wpml = new XMLWriter(new FileOutputStream(path + "waylines" + ".wpml"), format);
        wpml.write(document);
        wpml.close();

        //文件压缩为zip
        FileUtil.fileToZip(path, path, taskId.toString());

        //上传oss

        String zipPath = path + taskId + ".zip";
        File zipFile = new File(zipPath);
        InputStream inputStream = new FileInputStream(zipFile);
        try {
            MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
            return minioUtil.upload(DJ_KML + taskId + ".zip", multipartFile);
        } catch (Exception e) {
            log.error("oss上传异常", e);
        } finally {
            inputStream.close();
            FileUtil.deleteFile(path);
        }
        return null;
    }

    //takeOffSecurityHeight 起飞高度  ellipsoidHeight全局航线高度 speed 速度
    public ObjectWriteResponse setTravelsV2Kml(UploadKmlDto uploadKmlDto, String taskId) throws Exception {
        //动作处理 云台偏向的动作执行完后要回中

        Element root = DocumentHelper.createElement("kml");
        Document document = DocumentHelper.createDocument(root);

        //根节点添加属性
        root.addAttribute("xmlns", "http://www.opengis.net/kml/2.2")
                .addAttribute("xmlns:wpml", "http://www.dji.com/wpmz/1.0.0");


        Element documentElement = root.addElement("Document");
        documentElement.addNamespace("wpml", "http://www.dji.com/wpmz/1.0.0");
        documentElement.addAttribute("xmlns:wpml", "http://www.dji.com/wpmz/1.0.0");
        documentElement.addElement("wpml:createTime").addText(String.valueOf(System.currentTimeMillis()));
        documentElement.addElement("wpml:updateTime").addText(String.valueOf(System.currentTimeMillis()));

        Element missionConfig = documentElement.addElement("wpml:missionConfig");
        missionConfig.addElement("wpml:flyToWaylineMode").addText("safely");
        //航线结束动作goHome：飞行器完成航线任务后，退出航线模式并返航。
        //noAction：飞行器完成航线任务后，退出航线模式。
        //autoLand：飞行器完成航线任务后，退出航线模式并原地降落。
        //gotoFirstWaypoint：飞行器完成航线任务后，立即飞向航线起始点，到达后退出航线模式。* 注：以上动作执行过程，若飞行器退出了航线模式且进入失控状态，则会优先执行失控动作。
        missionConfig.addElement("wpml:finishAction").addText("goHome");
        //失控是否继续执行航线goContinue：继续执行航线 executeLostAction：退出航线，执行失控动作
        missionConfig.addElement("wpml:exitOnRCLost").addText("executeLostAction");
        //失控动作类型goBack：返航。飞行器从失控位置飞向起飞点
        //landing：降落。飞行器从失控位置原地降落
        //hover：悬停。飞行器从失控位置悬停
        missionConfig.addElement("wpml:executeRCLostAction").addText("goBack");
        //安全起飞高度m
        missionConfig.addElement("wpml:takeOffSecurityHeight").addText(uploadKmlDto.getTakeOffSecurityHeight());
        //全局航线过渡速度m/s
        missionConfig.addElement("wpml:globalTransitionalSpeed").addText(uploadKmlDto.getSpeed());

        //飞行器机型信息
        Element droneInfo = missionConfig.addElement("wpml:droneInfo");

        droneInfo.addElement("wpml:droneEnumValue").addText(uploadKmlDto.getDroneInfo().droneEnumValue);
        droneInfo.addElement("wpml:droneSubEnumValue").addText(uploadKmlDto.getDroneInfo().droneSubEnumValue);
        //负载机型信息
        Element payloadInfo = missionConfig.addElement("wpml:payloadInfo");
        payloadInfo.addElement("wpml:payloadEnumValue").addText(uploadKmlDto.getPayloadInfo().payloadEnumValue);
        payloadInfo.addElement("wpml:payloadSubEnumValue").addText(uploadKmlDto.getPayloadInfo().payloadSubEnumValue);
        payloadInfo.addElement("wpml:payloadPositionIndex").addText(uploadKmlDto.getPayloadInfo().payloadPositionIndex);


        Element folderElement = documentElement.addElement("Folder");//添加一个目录
        folderElement.addElement("wpml:templateType").addText("waypoint");
        folderElement.addElement("wpml:useGlobalTransitionalSpeed").addText(uploadKmlDto.getSpeed());
        folderElement.addElement("wpml:templateId").addText(taskId.toString());
        folderElement.addElement("wpml:waylineId").addText(taskId.toString());
        Element waylineCoordinateSysParam = folderElement.addElement("wpml:waylineCoordinateSysParam");
        waylineCoordinateSysParam.addElement("wpml:coordinateMode").addText("WGS84");
        waylineCoordinateSysParam.addElement("wpml:heightMode").addText("EGM96");
        waylineCoordinateSysParam.addElement("wpml:ellipsoidHeight").addText(uploadKmlDto.getEllipsoidHeight());
        waylineCoordinateSysParam.addElement("wpml:height").addText(uploadKmlDto.getEllipsoidHeight());
        waylineCoordinateSysParam.addElement("wpml:positioningType").addText("GPS");

        folderElement.addElement("wpml:autoFlightSpeed").addText(uploadKmlDto.getSpeed());
        //执行高度模式
        folderElement.addElement("wpml:transitionalSpeed").addText(uploadKmlDto.getSpeed());
        folderElement.addElement("wpml:gimbalPitchMode").addText("usePointSetting");
        folderElement.addElement("wpml:globalWaypointHeadingParam").addElement("wpml:waypointHeadingMode").addText("followWayline");
        folderElement.addElement("wpml:globalWaypointTurnMode").addText("toPointAndStopWithDiscontinuityCurvature");


        //生成点位图标数据
        int i = 0;
        for (TravelRecordRequest travelRecord : uploadKmlDto.getTravelRecordRequests()) {
            //在文件夹中添加一个地标
            Element placeMarkElement = folderElement.addElement("Placemark");
            Element pointElement = placeMarkElement.addElement("Point");
            // pointElement.addElement("altitudeMode").addText("clampToGround");
            //添加点位的经纬度坐标以及高度(显示时绘制高度m)
            pointElement.addElement("coordinates").addText(travelRecord.lng + "," + travelRecord.lat);//可以是是任何几何形状的子元素，定义每一个点的经度、纬度和高度(按照严格的顺序). 多个点使用空格隔开，经纬度按照WGS84标准.
            placeMarkElement.addElement("wpml:index").addText(String.valueOf(i));
            placeMarkElement.addElement("wpml:ellipsoidHeight").addText(uploadKmlDto.getEllipsoidHeight());
            placeMarkElement.addElement("wpml:height").addText(travelRecord.height);
            //   placeMarkElement.addElement("wpml:useGlobalHeight").addText("1");
            placeMarkElement.addElement("wpml:useGlobalSpeed").addText("1");
            placeMarkElement.addElement("wpml:useGlobalHeadingParam").addText("1");
            placeMarkElement.addElement("wpml:useGlobalTurnParam").addText("1");
            placeMarkElement.addElement("wpml:useStraightLine").addText("0");
            placeMarkElement.addElement("wpml:gimbalPitchAngle").addText("0");
            TravelRecordRequest.analysisPoint(travelRecord, placeMarkElement);
            i++;
        }

        Element payloadParamElement = folderElement.addElement("wpml:payloadParam");
        payloadParamElement.addElement("wpml:payloadPositionIndex").addText(uploadKmlDto.getPayloadParam().payloadPositionIndex);
        payloadParamElement.addElement("wpml:focusMode").addText(uploadKmlDto.getPayloadParam().focusMode);
        payloadParamElement.addElement("wpml:meteringMode").addText(uploadKmlDto.getPayloadParam().focusMode);
        payloadParamElement.addElement("wpml:returnMode").addText(uploadKmlDto.getPayloadParam().returnMode);
        payloadParamElement.addElement("wpml:samplingRate").addText(uploadKmlDto.getPayloadParam().samplingRate);
        payloadParamElement.addElement("wpml:scanningMode").addText(uploadKmlDto.getPayloadParam().scanningMode);
        payloadParamElement.addElement("wpml:imageFormat").addText(uploadKmlDto.getPayloadParam().imageFormat);

        //新建文件夹
        String originPath = TMP_PATH + System.currentTimeMillis() + "/";
        String path = originPath + "wpmz/";
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        //创建kml到本地
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter kml = new XMLWriter(new FileOutputStream(path + "template" + ".kml"), format);
        kml.write(document);
        kml.close();

        XMLWriter wpml = new XMLWriter(new FileOutputStream(path + "waylines" + ".wpml"), format);
        wpml.write(document);
        wpml.close();

        //文件压缩为zip
        FileUtil.fileToZip(originPath, originPath, taskId);

        //上传oss
        String zipPath = originPath + taskId + ".zip";
        File zipFile = new File(zipPath);
        InputStream inputStream = new FileInputStream(zipFile);
        try {
            MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
            return minioUtil.upload(DJ_KML + taskId + ".kmz", multipartFile);
        } catch (Exception e) {
            log.error("oss上传异常", e);
        } finally {
            inputStream.close();
            FileUtil.deleteFile(originPath);
        }
        return null;
    }


}
